home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc Development Framework / ODFDev / ODF / Examples / Clock / Sources / ClockFra.cpp next >
Encoding:
Text File  |  1995-11-08  |  16.7 KB  |  563 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                ClockFra.cpp
  4. //    Release Version:    $ 1.0d11 $
  5. //
  6. //    Copyright:    © 1993, 1995 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #ifndef CLOCKFRA_H
  11. #include "ClockFra.h"
  12. #endif
  13.  
  14. #ifndef CLOCKPAR_H
  15. #include "ClockPar.h"
  16. #endif
  17.  
  18. #ifndef CLOCKDEF_H
  19. #include "ClockDef.h"
  20. #endif
  21.  
  22. // ----- Part Layer -----
  23.  
  24. #ifndef FWUTIL_H
  25. #include "FWUtil.h"
  26. #endif
  27.  
  28. #ifndef FWITERS_H
  29. #include "FWIters.h"
  30. #endif
  31.  
  32. // ----- OS Layer -----
  33.  
  34. #ifndef FWTXTSHP_H
  35. #include "FWTxtShp.h"
  36. #endif
  37.  
  38. #ifndef FWRECSHP_H
  39. #include "FWRecShp.h"
  40. #endif
  41.  
  42. #ifndef FWLINSHP_H
  43. #include "FWLinShp.h"
  44. #endif
  45.  
  46. #ifndef FWOVLSHP_H
  47. #include "FWOvlShp.h"
  48. #endif
  49.  
  50. #ifndef FWODGEOM_H
  51. #include "FWODGeom.h"
  52. #endif
  53.  
  54. #ifndef FWTXTBOX_H
  55. #include "FWTxtBox.h"
  56. #endif
  57.  
  58. #ifndef FWCFMRES_H
  59. #include "FWCFMRes.h"
  60. #endif
  61.  
  62. #ifndef FWRESACC_H
  63. #include "FWResAcc.h"
  64. #endif
  65.  
  66. #ifndef FWRESTYP_H
  67. #include "FWResTyp.h"
  68. #endif
  69.  
  70. #ifndef FWFXMATH_H
  71. #include "FWFxMath.h"
  72. #endif
  73.  
  74. //========================================================================================
  75. // RunTime information
  76. //========================================================================================
  77.  
  78. #ifdef FW_BUILD_MAC
  79. #pragma segment odfclock
  80. #endif
  81.  
  82. FW_DEFINE_CLASS_M1 (CClockFrame, FW_CFrame)
  83.  
  84. //========================================================================================
  85. // Constants
  86. //========================================================================================
  87.  
  88. const FW_CFixed kClockRadius = FW_IntToFixed(100);    // In logical units
  89. const FW_CFixed kFxPI = FW_DoubleToFixed(3.1415926);
  90.  
  91. //========================================================================================
  92. // class CClockFrame
  93. //========================================================================================
  94.  
  95. //----------------------------------------------------------------------------------------
  96. // CClockFrame::CClockFrame
  97. //----------------------------------------------------------------------------------------
  98.  
  99. CClockFrame::CClockFrame(Environment* ev, ODFrame* odFrame, FW_CPresentation* presentation, CClockPart* clockPart) :
  100.     FW_CFrame(ev, odFrame, presentation, clockPart),
  101.     fMapping(FW_kCustomConstrained)
  102. {
  103.     fClockPart = clockPart;
  104.     
  105.     // ----- Load the face string ("OpenDoc") -----
  106.     {
  107.         FW_CSharedLibraryResourceFile resFile;
  108.         ::FW_LoadStringByID(resFile, kClockFaceStrings, MULTISTRINGRES, kClockOpenDocString, fFaceString);
  109.     }
  110. }
  111.  
  112. //----------------------------------------------------------------------------------------
  113. // CClockFrame::~CClockFrame
  114. //----------------------------------------------------------------------------------------
  115.  
  116. CClockFrame::~CClockFrame()
  117. {
  118. }
  119.  
  120. //----------------------------------------------------------------------------------------
  121. // CClockFrame::FacetAdded
  122. //----------------------------------------------------------------------------------------
  123.  
  124. void CClockFrame::FacetAdded(Environment* ev, ODFacet* facet)
  125. {
  126.     FW_CFrame::FacetAdded(ev, facet);
  127.     
  128.     // ----- First reset the mapping. Because ResetMapping needs the window
  129.     // ----- we have to wait for FacetAdded before calling ResetMapping the first time
  130.     this->ResetMapping(ev);
  131.  
  132.     // ----- Calculate a default rectangle size for a digital clock
  133.     FW_CFacetContext fc(ev, facet, NULL);
  134.     
  135.     FW_CString32 digitalString;
  136.     {
  137.         FW_CSharedLibraryResourceFile resFile;
  138.         ::FW_LoadStringByID(resFile, kClockFaceStrings, MULTISTRINGRES, kClockDigitalWidthString, digitalString);
  139.     }
  140.     
  141.     FW_CTextShape textShape(
  142.         digitalString,
  143.         FW_IntToFixed(0),
  144.         FW_IntToFixed(0),
  145.         FW_PFont(FW_kTimes, FW_kPlain, FW_IntToFixed(12)),
  146.         FW_kTextAlignLeft | FW_kTextAlignBaseLine);
  147.         
  148.     textShape.GetBounds(fc, fDigitalClockRect);
  149.     
  150.     fDigitalClockRect.Inset(FW_IntToFixed(-3), FW_IntToFixed(-3));
  151.     
  152.     this->UpdateUsedAndActiveShapes(ev);
  153. }
  154.  
  155. //----------------------------------------------------------------------------------------
  156. //    CClockFrame::ChangeClockType
  157. //----------------------------------------------------------------------------------------
  158. //    If I switch to analog and my frame is smaller than ff(80) try to request something bigger
  159.  
  160. void CClockFrame::ChangeClockType(Environment* ev, short newClockType)
  161. {
  162.     if (!IsTopFrame(ev) && newClockType == kAnalogClock)
  163.     {
  164.         FW_CRect frameBounds = GetBounds(ev);
  165.         FW_CFixed height = frameBounds.Height();
  166.         FW_CFixed width = frameBounds.Width();
  167.         FW_CFixed min = FW_Minimum(height, width);
  168.         
  169.         if (min < FW_IntToFixed(80))
  170.         {
  171.             FW_CAcquiredODShape askedShape = ::FW_NewODShape(ev, FW_CRect(FW_kZeroPoint, FW_IntToFixed(80), FW_IntToFixed(80)));
  172.             this->RequestFrameShape(ev, askedShape);
  173.         }    
  174.     }
  175.     
  176.     UpdateUsedAndActiveShapes(ev);
  177.     ResetMapping(ev);
  178.     Invalidate(ev);
  179. }
  180.  
  181. //----------------------------------------------------------------------------------------
  182. //    CClockFrame::AdjustUsedShape
  183. //----------------------------------------------------------------------------------------
  184. //    'suggestedUsedShape' is equal to the frame shape
  185.  
  186. ODShape* CClockFrame::AdjustUsedShape(Environment* ev, ODShape* suggestedUsedShape)
  187. {    
  188.     FW_CRect usedRect = FW_GetShapeBoundingBox(ev, suggestedUsedShape);
  189.  
  190.     ODShape* newUsedShape;
  191.     if (fClockPart->GetClockType() == kAnalogClock)
  192.     {        
  193.         FW_CRect rect(usedRect);
  194.         FW_CFixed height = usedRect.Height();
  195.         FW_CFixed width = usedRect.Width();
  196.         
  197.         if (height < width)
  198.             rect.right = rect.left + height;
  199.         else
  200.             rect.bottom = rect.top + width;
  201.         rect.PlaceInCenter(usedRect);
  202.         
  203.         newUsedShape = ::FW_CreateOvalODShape(ev, rect);
  204.     }
  205.     else
  206.     {    
  207.         FW_CRect rect(fDigitalClockRect);
  208.         rect.PlaceInCenter(usedRect);
  209.         
  210.         newUsedShape = ::FW_NewODShape(ev, rect);
  211.     }
  212.     
  213.     return newUsedShape;
  214. }
  215.  
  216. //----------------------------------------------------------------------------------------
  217. //    CClockFrame::AdjustActiveShape
  218. //----------------------------------------------------------------------------------------
  219. //    [HLX] Because OpenDoc uses the Frame shape as the default active shape I need to 
  220. //    adjust my active shape too.
  221.  
  222. ODShape* CClockFrame::AdjustActiveShape(Environment* ev, ODFacet* facet, ODShape* suggestedActiveShape)
  223. {
  224.     suggestedActiveShape->Acquire(ev);
  225.     return suggestedActiveShape;
  226. }
  227.  
  228. //----------------------------------------------------------------------------------------
  229. // CClockFrame::FrameShapeChanged
  230. //----------------------------------------------------------------------------------------
  231.  
  232. void CClockFrame::FrameShapeChanged(Environment* ev)
  233. {
  234.     FW_CFrame::FrameShapeChanged(ev);
  235.     
  236.     this->ResetMapping(ev);
  237.     
  238.     this->Invalidate(ev);        // Invalidate frame shape
  239.     this->GetODFrame(ev)->InvalidateActiveBorder(ev);
  240. }
  241.  
  242. //----------------------------------------------------------------------------------------
  243. // CClockFrame::UpdateClock
  244. //----------------------------------------------------------------------------------------
  245.  
  246. void CClockFrame::UpdateClock(Environment* ev, const FW_CTime& time)
  247. {
  248.     FW_CFrameFacetIterator facets(ev, this);
  249.     for (ODFacet* clockFacet = (ODFacet*)facets.First(ev); facets.IsNotComplete(ev); clockFacet = (ODFacet*)facets.Next(ev))
  250.     {
  251.         FW_CFacetContext fc(ev, clockFacet);
  252.         
  253.         if (fClockPart->GetClockType() == kAnalogClock)
  254.         {
  255.              fc.SetMapping(fMapping);
  256.             UpdateAnalogClock(ev, fc, time);
  257.          }
  258.         else
  259.             UpdateDigitalClock(ev, fc, time);
  260.     }
  261. }
  262.  
  263. //----------------------------------------------------------------------------------------
  264. // CClockFrame::Draw
  265. //----------------------------------------------------------------------------------------
  266.  
  267. void CClockFrame::Draw(Environment* ev, ODFacet* odFacet, ODShape* invalidShape)
  268. {
  269.     FW_CFacetContext fc(ev, odFacet, invalidShape);
  270.  
  271.     // [HLX] This will be moved into an erase adorner
  272.     if (IsRoot(ev))
  273.     {
  274.         FW_CRect invalidRect;
  275.         fc.GetClipRect(invalidRect);
  276.  
  277. #ifdef FW_BUILD_MAC
  278.         FW_PInk ink(FW_kRGBWhite,
  279.                     FW_kRGBWhite,
  280.                     FW_kErase);
  281. #else
  282.         FW_PInk ink(FW_CColor(::GetSysColor(COLOR_WINDOWTEXT), 0),
  283.                     FW_CColor(::GetSysColor(COLOR_APPWORKSPACE), 0),
  284.                     FW_kErase);
  285. #endif
  286.         FW_CRectShape::RenderRect(fc, invalidRect, FW_kFill, ink);
  287.     }
  288.  
  289.     FW_CTime lastTime = fClockPart->GetLastTime();
  290.     
  291.     if (fClockPart->GetClockType() == kAnalogClock)
  292.     {
  293.         fc.SetMapping(fMapping);
  294.         
  295.         this->DrawClockFace(ev, fc);
  296.         
  297.         this->DrawSecondHand(ev, fc, FW_IntToFixed(lastTime.GetSecond()));
  298.         this->DrawMinuteHand(ev, fc, FW_IntToFixed(lastTime.GetMinute()));
  299.         this->DrawHourHand(ev, fc, FW_IntToFixed(lastTime.GetHour()), FW_IntToFixed(lastTime.GetMinute()));
  300.     }
  301.     else
  302.         UpdateDigitalClock(ev, fc, lastTime);
  303. }
  304.  
  305. //----------------------------------------------------------------------------------------
  306. // CClockFrame::DrawClockFace
  307. //----------------------------------------------------------------------------------------
  308.  
  309. static void DrawTicks(FW_CFacetContext& fc, FW_CLineShape& lineShape, 
  310.                      FW_CFixed xStart, FW_CFixed yStart, 
  311.                      FW_CFixed xEnd, FW_CFixed yEnd)
  312. {
  313.     lineShape.SetLineStart(xStart, yStart);
  314.     lineShape.SetLineEnd(xEnd, yEnd);
  315.     lineShape.Render(fc);
  316.     
  317.     lineShape.SetLineStart(-xStart, yStart);
  318.     lineShape.SetLineEnd(-xEnd, yEnd);
  319.     lineShape.Render(fc);
  320.  
  321.     lineShape.SetLineStart(xStart, -yStart);
  322.     lineShape.SetLineEnd(xEnd, -yEnd);
  323.     lineShape.Render(fc);
  324.     
  325.     lineShape.SetLineStart(-xStart,-yStart);
  326.     lineShape.SetLineEnd(-xEnd, -yEnd);
  327.     lineShape.Render(fc);
  328. }
  329.  
  330. //----------------------------------------------------------------------------------------
  331. // CClockFrame::ResetMapping
  332. //----------------------------------------------------------------------------------------
  333.  
  334. void CClockFrame::ResetMapping(Environment* ev)
  335. {
  336.     FW_CPoint logicalExtent(kClockRadius.MultipliedByInt(2), kClockRadius.MultipliedByInt(2));
  337.     FW_CPoint deviceExtent = GetExtent(ev);
  338.  
  339.     fMapping.SetExtents(ev, logicalExtent, deviceExtent);
  340.     fMapping.SetDeviceOrigin(ev, deviceExtent.x.Half(), deviceExtent.y.Half());
  341. }
  342.  
  343. //----------------------------------------------------------------------------------------
  344. // CClockFrame::DrawClockFace
  345. //----------------------------------------------------------------------------------------
  346.  
  347. void CClockFrame::DrawClockFace(Environment* ev, FW_CFacetContext& fc)
  348. {
  349.     // ----- Erase under the clock -----
  350.     FW_CRect ovalRect(-kClockRadius, -kClockRadius, kClockRadius, kClockRadius);
  351.     
  352.     FW_COvalShape::RenderOval(
  353.         fc,
  354.         ovalRect,
  355.         FW_kFill,
  356.         FW_kWhiteEraseInk);
  357.     
  358.     FW_COvalShape::RenderOval(
  359.         fc,
  360.         ovalRect,
  361.         FW_kFrame,
  362.         FW_kNormalInk,
  363.         FW_PStyle(FW_IntToFixed(2)));
  364.  
  365.     // ----- Render the "OpenDoc" string -----
  366.     FW_CTextShape::RenderText(
  367.         fc,
  368.         fFaceString,
  369.         FW_CPoint(FW_IntToFixed(0), -kClockRadius.Half()),
  370.         FW_PFont(FW_kHelvetica, FW_kItalic, kClockRadius.DividedByInt(5)),
  371.         FW_kTextAlignHCenter | FW_kTextAlignBaseLine);
  372.     
  373.     // Use the symmetry of the clock face to speed up the calculations for drawing the face
  374.     // We only need to calculate points for 45 degrees of the circle.  The remaining points can
  375.     // be inferred from these points
  376.     
  377.     short angle = 0;
  378.     short fiveMinute = 0;
  379.  
  380.     FW_PStyle lineStyle = FW_ODFixedToFixed(0x00008000);    // 1/2
  381.     FW_CLineShape lineShape;
  382.     lineShape.SetStyle(lineStyle);
  383.     
  384.     FW_CFixed xStart, yStart, xEnd, yEnd;
  385.  
  386.     FW_CFixed radius = kClockRadius - FW_IntToFixed(2);    // 2 logical unit
  387.     while (angle < 45)
  388.     {
  389.         // ----- convert angle to radians -----
  390.         FW_CFixed radians = (kFxPI * FW_IntToFixed(90 - angle)).DividedByInt(180);
  391.         FW_CFixed cosRadian = radians.Cos();
  392.         FW_CFixed sinRadian = radians.Sin();
  393.  
  394.         xStart = radius * cosRadian;
  395.         yStart = radius * sinRadian;
  396.         
  397.         FW_CFixed tickRadius;
  398.         if (fiveMinute == 0)
  399.         {
  400.             tickRadius = radius - radius.DividedByInt(10);
  401.             fiveMinute = 4;
  402.         }
  403.         else
  404.         {
  405.             tickRadius = radius - radius.DividedByInt(20);
  406.             fiveMinute--;
  407.         }
  408.  
  409.         xEnd = tickRadius * cosRadian;
  410.         yEnd = tickRadius * sinRadian;
  411.  
  412.         DrawTicks(fc, lineShape, xStart, yStart, xEnd, yEnd);
  413.         
  414.         DrawTicks(fc, lineShape, yStart, xStart, yEnd, xEnd);
  415.  
  416.         angle += 6;
  417.     }
  418. }
  419.  
  420. //----------------------------------------------------------------------------------------
  421. //    CalcPoint
  422. //----------------------------------------------------------------------------------------
  423.  
  424. static FW_CPoint CalcPoint(FW_CFixed radius, FW_CFixed angle)
  425. {
  426.     FW_CPoint point(
  427.         radius * angle.Sin(),
  428.         - radius * angle.Cos());
  429.  
  430.     return point;
  431. }
  432.  
  433. //----------------------------------------------------------------------------------------
  434. // ::DegreesToRadians
  435. //----------------------------------------------------------------------------------------
  436.  
  437. static inline FW_CFixed DegreesToRadians(FW_CFixed degrees)
  438. {
  439.     return (degrees * kFxPI).DividedByInt(180);
  440. }
  441.  
  442. //----------------------------------------------------------------------------------------
  443. // CClockFrame::DrawHourHand
  444. //----------------------------------------------------------------------------------------
  445.  
  446. void CClockFrame::DrawHourHand(Environment* ev, 
  447.                                 FW_CFacetContext& fc, 
  448.                                 FW_CFixed hour, 
  449.                                 FW_CFixed minute)
  450. {
  451.     FW_CFixed hourRadius = kClockRadius.DividedByInt(2);        // Make the hour hand short and stubby
  452.  
  453.     if (hour > FW_IntToFixed(11))
  454.         hour -= FW_IntToFixed(12);
  455.     
  456.     // ----- Divide the clock face into degrees.  
  457.     // ----- Hour hand falls on every five minutes or every 30 degrees
  458.     FW_CFixed radians = ::DegreesToRadians(hour.MultipliedByInt(30) + minute.Half());
  459.     
  460.     FW_CPoint newPoint = ::CalcPoint(hourRadius, radians);
  461.  
  462.     FW_PStyle style(FW_IntToFixed(3));
  463.     FW_CLineShape lineShape(FW_kZeroPoint, newPoint);
  464.     lineShape.SetInk(FW_kInvertInk);
  465.     lineShape.SetStyle(style);
  466.     lineShape.Render(fc);
  467. }
  468.  
  469. //----------------------------------------------------------------------------------------
  470. // CClockFrame::DrawMinuteHand
  471. //----------------------------------------------------------------------------------------
  472.  
  473. void CClockFrame::DrawMinuteHand(Environment* ev, 
  474.                                 FW_CFacetContext& fc, 
  475.                                 FW_CFixed minute)
  476. {
  477.     FW_CFixed minuteRadius = kClockRadius * FW_DoubleToFixed(0.8);  // Make the minute hand longer than the hour hand
  478.     
  479.     // ----- Divide the clock face into degrees.  
  480.     // ----- (360 degrees divided by 60 minutes is 6 degrees per minute)
  481.     FW_CFixed radians = ::DegreesToRadians(minute.MultipliedByInt(6));
  482.  
  483.     FW_CPoint newPoint = ::CalcPoint(minuteRadius, radians);
  484.  
  485.     FW_PStyle style(FW_IntToFixed(2));
  486.     FW_CLineShape lineShape(FW_kZeroPoint, newPoint);
  487.     lineShape.SetInk(FW_kInvertInk);
  488.     lineShape.SetStyle(style);
  489.     lineShape.Render(fc);
  490. }
  491.  
  492. //----------------------------------------------------------------------------------------
  493. // CClockFrame::DrawSecondHand
  494. //----------------------------------------------------------------------------------------
  495.  
  496. void CClockFrame::DrawSecondHand(Environment* ev, 
  497.                                 FW_CFacetContext& fc, 
  498.                                 FW_CFixed second)
  499. {
  500.     FW_CFixed secondRadius = kClockRadius * FW_DoubleToFixed(0.9);    // A nice sweeping second hand
  501.  
  502.     // ----- Divide the clock face into degrees.  
  503.     // ----- (360 degrees divided by 60 seconds is 6 degrees per second)
  504.     FW_CFixed radians = ::DegreesToRadians(second.MultipliedByInt(6));
  505.     
  506.     FW_CPoint newPoint = ::CalcPoint(secondRadius, radians);
  507.  
  508.     FW_CLineShape lineShape(FW_kZeroPoint, newPoint);
  509.     lineShape.SetInk(FW_kInvertInk);
  510.     lineShape.Render(fc);
  511. }
  512.  
  513. //----------------------------------------------------------------------------------------
  514. // CClockFrame::UpdateAnalogClock
  515. //----------------------------------------------------------------------------------------
  516.  
  517. void CClockFrame::UpdateAnalogClock(Environment* ev, 
  518.                                     FW_CFacetContext& fc, 
  519.                                     const FW_CTime& time)
  520. {
  521.     FW_CTime lastTime = fClockPart->GetLastTime();
  522.     
  523.     // ----- Since we're called every second go ahead and update the second hand
  524.     this->DrawSecondHand(ev, fc, FW_IntToFixed(lastTime.GetSecond()));
  525.     this->DrawSecondHand(ev, fc, FW_IntToFixed(time.GetSecond()));
  526.  
  527.     if (lastTime.GetMinute() != time.GetMinute())
  528.     {
  529.         this->DrawMinuteHand(ev, fc, FW_IntToFixed(lastTime.GetMinute()));
  530.         this->DrawMinuteHand(ev, fc, FW_IntToFixed(time.GetMinute()));
  531.         
  532.         this->DrawHourHand(ev, fc, FW_IntToFixed(lastTime.GetHour()), FW_IntToFixed(lastTime.GetMinute()));
  533.         this->DrawHourHand(ev, fc, FW_IntToFixed(time.GetHour()), FW_IntToFixed(time.GetMinute()));
  534.     }
  535. }
  536.  
  537. //----------------------------------------------------------------------------------------
  538. // CClockFrame::UpdateDigitalClock
  539. //----------------------------------------------------------------------------------------
  540.  
  541. void CClockFrame::UpdateDigitalClock(Environment* ev, 
  542.                                     FW_CFacetContext& fc, 
  543.                                     const FW_CTime& time)
  544. {
  545.     FW_CString255 timeString;
  546.     time.GetTimeString(timeString, TRUE);
  547.  
  548.     FW_CAcquiredODShape aqUsedShape(this->AcquireUsedShape(ev, NULL));
  549.     FW_CRect usedShapeRect = FW_GetShapeBoundingBox(ev, aqUsedShape);
  550.     
  551.     FW_CRectShape rectShape(usedShapeRect, FW_kFill);
  552.     rectShape.SetInk(FW_kWhiteEraseInk);
  553.     rectShape.Render(fc);
  554.     
  555.     rectShape.SetRenderVerb(FW_kFrame);
  556.     rectShape.Render(fc);
  557.     
  558.     FW_CString32 fontName(FW_kSystemFont);
  559.     FW_PFont fontStyle(fontName, FW_kPlain, FW_IntToFixed(12));
  560.     FW_CTextBoxShape::RenderTextBox(fc, timeString, usedShapeRect, fontStyle, FW_kTextBoxJustifyHCenter);
  561. }
  562.  
  563.